home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacWorld 1997 September
/
Macworld (1997-09).dmg
/
Shareware World
/
Utilities
/
Text Processing
/
Alpha
/
Tcl
/
SystemCode
/
fill.tcl
< prev
next >
Wrap
Text File
|
1997-03-25
|
12KB
|
400 lines
####################################################################
#
# Much by Vince Darley.
#
# created: 3/7/95 {7:49:47 pm}
# last update: 16/5/96
# Author: Vince Darley
# E-mail: <mailto:vince@das.harvard.edu>
# mail: Division of Applied Sciences, Harvard University
# Oxford Street, Cambridge MA 02138, USA
# www: <http://www.fas.harvard.edu/~darley/>
#
####################################################################
##
# Here's a brief explanation of the smart fillParagraph routines
#
# 'fillParagraph'
# If there's a selection, then fill all paragraphs in that
# selection. If not then fill the paragraph surrounding the
# insertion point. The definition of a 'paragraph' may be
# mode dependent (see paraStart, paraFinish)
#
# 'fillOneParagraph'
# Fills the single paragraph surrounding the insertion point.
# If called with parameter '0', it doesn't bother to remember
# where the insertion point was, which makes multiple paragraph
# fills quicker when called by 'fillParagraph'
#
# 'rememberWhereYouAre'
# Given the start of a paragraph and the point to remember,
# this creates a record stored in '__g_remember_pos' so that
# the following function can find that spot later, even after
# the paragraph has had space/tabs/new-lines meddled with.
#
# 'goBackToWhereYouWere'
# Given the beginning and end of a selection, where the beginning
# corresponds to a previous call of 'rememberWhereYouAre', this
# procedure will move the insertion point to the correct place.
#
# 'texParaCommands'
# A variable containing the bulk of a regexp for paragraph
# indicators in 'TeX' mode.
#
# 'paraStart'
# Finds the start of the paragraph containing the insertion point.
#
# 'paraFinish'
# Finds the end of the paragraph containing the insertion point.
##
proc fillParagraph {} {
if {[getPos] == [selEnd]} {
fillOneParagraph
} else {
set start [getPos]
set end [selEnd]
set p $start
while { $p < $end && $p < [maxPos]} {
goto $p
set p [fillOneParagraph 0]
}
goto $start
}
}
proc rememberWhereYouAre { startPara pos } {
global __g_remember_str
set srem [expr $pos -20 < $startPara ? $startPara : $pos - 20]
set __g_remember_str [quoteExpr2 [getText $srem $pos ]]
regsub -all "\[ \t\r\]+" $__g_remember_str {[ \t\r]+} __g_remember_str
}
proc goBackToWhereYouWere { start end } {
global __g_remember_str
if { $__g_remember_str != "" } {
regexp -indices ".*(${__g_remember_str}).*" [getText $start $end] wholematch submatch
set p [expr [info exists submatch] ? \
[expr $start + 1 + [lindex $submatch 1]] : $end]
goto [expr $p >= $end ? $end -1 : $p]
} else {
goto $start
}
}
##
# -------------------------------------------------------------------------
#
# "getLeadingIndent" --
#
# Find the indentation of the line containing 'pos', and convert it
# to a minimal form of tabs followed by spaces. If 'size'
# is given, then the variable of that name is set to the length of
# the indent. Similarly 'halftab' can be set to half a tab.
# -------------------------------------------------------------------------
##
proc getLeadingIndent { pos {size ""} {halftab ""} } {
# get the leading whitespace of the current line
set res [search -s -n -f 1 -r 1 "^\[ \t\]*" [lineStart $pos]]
# convert it to minimal form: tabs then spaces, stored in 'front'
getWinInfo a
set sp [string range " " 1 $a(tabsize) ]
regsub -all $sp [eval getText $res] "\t" front
regsub -all "\[ \]+\t" $front "\t" front
if { $size != "" } {
upvar $size ind
# get the length of the indent
regsub -all "\t" $front $sp lfront
set ind [string length $lfront]
}
if { $halftab != "" } {
upvar $halftab ht
# get the length of half a tab
set ht [string range " " 1 [expr $a(tabsize)/2]]
}
return $front
}
proc fillOneParagraph { {remember 1} } {
global leftFillColumn fillColumn doubleSpaces
set pos [getPos]
set start [paraStart $pos]
set end [paraFinish $pos]
if $remember { rememberWhereYouAre $start $pos }
# Get the leading whitespace of the current line and store length in 'left'
set front [getLeadingIndent $pos left]
# fill the text
regsub -all "\[ \t\r\]+" [string trim [getText $start $end]] " " text
# turn single spaces at end of sentences into double
if {$doubleSpaces} {regsub -all {(([^A-Z@]|\\@)[.?!]("|'|'')?([])])?) } $text {\1 } text}
# if {$doubleSpaces} {regsub -all {(([^A-Z@]|\\@)[.?!][])'"]?) } $text {\1 } text}
# temporarily adjust the fillColumns
set ol $leftFillColumn
set or $fillColumn
set leftFillColumn 0
set fillColumn [expr $fillColumn - $left]
# break and indent the paragraph
regsub -all "\r" "\r[string trimright [breakIntoLines $text]]" "\r${front}" text
# don't replace if nothing's changed
if { "$text\r" != "\r[getText $start $end]" } {
replaceText $start $end "[string range $text 1 end]\r"
if $remember { goBackToWhereYouWere $start [expr $start + [string length $text]] }
}
set leftFillColumn $ol
set fillColumn $or
# in case we wish to fill a region
return $end
}
##
# -------------------------------------------------------------------------
#
# "paraStart" -- "paraFinish"
#
# Newly simplified version with fewer regexp '()' pairs. Also I think
# it deals better with TeX comments than the old regexp.
#
# "Start": It's pretty clear for non TeX modes how this works. The only
# key is that we start at the beginning of the current line and look back.
# We then have a quick check for whether we found that very beginning (in
# which case return it) or if not (in which case we have found the end of
# the previous paragraph) we move forward a line.
#
# "Finish": The only addition is the need for an additional check for
# stuff which explicitly ends lines.
#
# Results:
# The start/finish position of the paragraph containing the given 'pos'
#
# --Version--Author------------------Changes-------------------------------
# 1.1 <vince@das.harvard.edu> Cut down on '()' pairs
# 1.2 Vince - March '96 Better filling for TeX tables ('hline')
# 1.3 Johan Linde - May '96 Now sensitive to HTML elements
# -------------------------------------------------------------------------
##
proc paraStart {pos} {
global mode texParaCommands htmlParaCommands
if {$pos == [maxPos]} {incr pos -1}
set pos [lineStart $pos]
if { $mode == "TeX" || $mode == "Bib" } {
set startPara {^[ \t]*$|\\\\[ \t]*$|%.*$|\\h+line[ \t]*$|\$\$[ \t]*$|^[ \t]*(\\(}
append startPara $texParaCommands {)(\[.*\]|\{.*\}|•)*[ \t]*)+$}
} elseif {$mode == "HTML"} {
set startPara {^[ \t]*$|</?(}
append startPara $htmlParaCommands {)([ \t\r]+[^>]*>|>)}
} else {
set startPara {^([ \t]*|([\\%].*))$}
}
set res [search -s -n -f 0 -r 1 -l 0 "$startPara" $pos]
if {![string length $res] || $res == "0 0" } {return 0}
if { [lindex $res 0] == $pos } {
return $pos
} else {
return [nextLineStart [lindex $res 0]]
}
}
set texParaCommands {\[|\]|begin|end|(protect\\)?label|(sub)*section|subfigure|paragraph|centerline|centering|caption|chapter|item|bibitem|intertext}
# The variable htmlParaCommands is defined in html.tcl.
proc paraFinish {pos} {
global mode texParaCommands htmlParaCommands
set pos [lineStart $pos]
set end [maxPos]
if { $mode == "TeX" || $mode == "Bib" } {
set endPara {^[ \t]*$|\$\$[ \t]*$|^[ \t]*(\\(}
append endPara $texParaCommands {)(\[.*\]|\{.*\}|•)*[ \t]*)+$}
} elseif {$mode == "HTML"} {
set endPara {^[ \t]*$|</?(}
append endPara $htmlParaCommands {)([ \t\r]+[^>]*>|>)}
} else {
set endPara {^([ \t]*|([\\%].*))$}
}
set res [search -s -n -f 1 -r 1 -l $end "$endPara" $pos]
if {![string length $res]} {return $end}
set cpos [lineStart [lindex $res 0] ]
if { $cpos == $pos } {
return [nextLineStart $cpos]
}
# A line which ends in '\\', '%...', '\hline', '\hhline'
# signifies the end of the current paragraph in TeX mode
# (the above checked for beginning of the next paragraph).
if { $mode == "TeX" || $mode == "Bib" } {
set res2 [search -s -n -f 1 -r 1 -l $end {((\\\\|\\h+line)[ \t]*|%.*)$} $pos]
if [string length $res2] {
if { [lindex $res2 0] < $cpos } {
return [nextLineStart [lindex $res2 0]]
}
}
}
return $cpos
}
proc sentenceParagraph {} {
set pos [getPos]
set start [paraStart $pos]
set finish [paraFinish $pos]
set t [string trim [getText $start $finish]]
set period [regexp {\.$} $t]
regsub -all "\[ \t\r\]+" $t " " text
regsub -all {\. } $text "Δ" text
set result ""
foreach line [split [string trimright $text {.}] "Δ"] {
if {[string length $line]} {
append result [breakIntoLines $line] ".\r"
}
}
if {!$period && [regexp {\.\r} $result]} {
set result [string trimright $result ".\r"]
append result "\r"
}
if {$result != [getText $start $finish]} {
replaceText $start $finish $result
}
goto $pos
}
proc getEndpts {} {
if {[getPos] == [selEnd]} {
set start [getPos]
set finish [getMark]
if {$start > $finish} {
set temp $start
set start $finish
set finish $temp
}
} else {
set start [getPos]
set finish [selEnd]
}
return [list $start $finish]
}
proc fillRegion {} {
global leftFillColumn
set ends [getEndpts]
set start [lineStart [lindex $ends 0]]
set finish [lindex $ends 1]
goto $start
set text [fillText $start $finish]
replaceText $start $finish [format "%$leftFillColumn\s" ""] $text "\r"
}
proc wrapParagraph {} {
set pos [getPos]
set start [paraStart $pos]
set finish [paraFinish $pos]
goto $start
wrapText $start $finish
goto $pos
}
proc wrapRegion {} {
set ends [getEndpts]
set start [lineStart [lindex $ends 0]]
set finish [lindex $ends 1]
if {$start == $finish} {
set finish [maxPos]
}
wrapText $start $finish
}
# Remove text from window, transform, and insert back into window.
proc fillText {from to} {
global doubleSpaces
set text [getText $from $to]
regexp {^ *} $text front
set text [string trim $text]
regsub -all "\[ \t\r\]+" $text " " text
if {$doubleSpaces} {regsub -all {(\.|\?|\!) } $text {\1 } text}
regsub -all "\r" [string trimright [breakIntoLines $text]] "\r${front}" text
return $front$text
}
proc paragraphToLine {} {
global fillColumn
global leftFillColumn
set fc $fillColumn
set lc $leftFillColumn
set fillColumn 10000
set leftFillColumn 0
fillRegion
set fillColumn $fc
set leftFillColumn $lc
}
proc lineToParagraph {} {
global fillColumn
global leftFillColumn
set fc $fillColumn
set fillColumn 75
set lc $leftFillColumn
set leftFillColumn 0
fillRegion
set fillColumn $fc
set leftFillColumn $lc
}
#set sentEnd {[.!?](\r| +)}
set sentEnd {(\r\r|[.!?](\r| +))}
set sentBeg {[\r ][A-Z]}
proc nextSentence {} {
global sentBeg sentEnd
if {![catch {search -s -f 1 -r 1 $sentEnd [getPos]} mtch]} {
if {![catch {search -s -f 1 -r 1 -i 0 $sentBeg [expr [lindex $mtch 1]-1]} mtch]} {
goto [expr [lindex $mtch 0]+1]
}
}
}
proc prevSentence {} {
global sentBeg sentEnd
if {[catch {search -s -f 0 -r 1 $sentBeg [expr [getPos]-2]} mtch]} return
if {![catch {search -s -f 0 -r 1 $sentEnd [lindex $mtch 1]} mtch]} {
if {![catch {search -s -f 1 -r 1 -i 0 $sentBeg [expr [lindex $mtch 1]-1]} mtch]} {
goto [expr [lindex $mtch 0]+1]
}
}
}
# 5 730 845 955
#===============================================================================
# Called by Alpha to do "soft wrapping"
proc softProc {pos start next} {
global leftFillColumn
goto $start
set finish [paraFinish $start]
set text [fillText $start $finish]
if {"${text}\r" != [getText $start $finish]} {
replaceText $start $finish [format "%$leftFillColumn\s" ""] $text "\r"
return 1
} else {
return 0
}
}